Skip to content

fix: an XSS in descriptions and two frontend bugs found by the coverage tests - #687

Merged
voc0der merged 3 commits into
mainfrom
fix/coverage-95-findings
Nov 14, 2026
Merged

voc0der merged 3 commits into
mainfrom
fix/coverage-95-findings

Conversation

@voc0der

@voc0der voc0der commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

Bugs that writing the coverage tests in #688 turned up, one commit each. Each has a regression test that fails without its fix.

  • Markup in a description ran in the player. The pipe that turns the addresses in a description into links built its HTML from the description as written and marked the result trusted. An <img onerror> or <script> in a description ran for anyone who opened the file, and a link could close its own href and add attributes such as onmouseover. Descriptions are written by whoever uploaded the file upstream, and the session token is in localStorage. Every part of a description is now escaped, only a whole http or https address becomes a link (with rel="noopener noreferrer"), and the result goes through Angular's sanitizer instead of around it. The unused parseText(), which built the same unescaped HTML, is gone.
  • A stored theme that does not exist left the page with no theme. loadConfig() passed it to setTheme(), which refused it, so no theme was applied and the theme toggle in the account menu threw on the theme that was never set, both in its template and when clicked. Clearing site data was the only way out. A stored theme that does not exist now counts as none, so the default applies, and a configured default that does not exist falls back to the light theme. Theme names are checked against the config's own keys, so constructor is not one.
  • The update dialog kept asking for progress after it closed. Its timer was never cleared, and the server ends an update by restarting with its status still saying it is updating, so a closed dialog asked four times a second until the page was reloaded. It also read the status before the first answer arrived, throwing every tick until then, and left failed requests unhandled. The timer now stops when the dialog closes, waits for the first answer, and keeps the last status up while the server restarts.

Validation on Node 26.13.0: 1,431 frontend tests passed; lint and the app type check passed. No backend changes.

@voc0der
voc0der merged commit d5f3486 into main Nov 14, 2026
14 checks passed
@voc0der
voc0der deleted the fix/coverage-95-findings branch November 14, 2026 23:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant